
package tij4.ch17;

import java.util.Random;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

//Performs some portion of a task:
class TaskPortion implements Runnable
{
	private static int counter = 0;
	private final int id = counter++;
	private static Random rand = new Random(47);
	private final CountDownLatch latch;

	TaskPortion(CountDownLatch latch)
	{
		this.latch = latch;
	}

	public void run()
	{
		try
		{
			doWork();
			latch.countDown();
		}
		catch (InterruptedException ex)
		{
			// Acceptable way to exit
		}
	}

	public void doWork() throws InterruptedException
	{
		TimeUnit.MILLISECONDS.sleep(rand.nextInt(2000));
		// print(this + "completed");
		System.out.println(this + "completed");
	}

	public String toString()
	{
		return String.format("%1$-3d ", id);
	}
}

// Waits on the CountDownLatch:
class WaitingTask implements Runnable
{
	private static int counter = 0;
	private final int id = counter++;
	private final CountDownLatch latch;

	WaitingTask(CountDownLatch latch)
	{
		this.latch = latch;
	}

	public void run()
	{
		try
		{
			latch.await();
			// print("Latch barrier passed for " + this);
			System.out.println("Latch barrier passed for " + this);
		}
		catch (InterruptedException ex)
		{
			// print(this + " interrupted");
			System.out.println(this + " interrupted");
		}
	}

	public String toString()
	{
		return String.format("WaitingTask %1$-3d ", id);
	}
}

public class CountDownLatchDemo
{
	static final int SIZE = 100;

	public static void main(String[] args) throws Exception
	{
		ExecutorService exec = Executors.newCachedThreadPool();
		// All must share a single CountDownLatch object:
		CountDownLatch latch = new CountDownLatch(SIZE);
		for (int i = 0; i < 10; i++)
			exec.execute(new WaitingTask(latch));
		for (int i = 0; i < SIZE; i++)
			exec.execute(new TaskPortion(latch));
		print("Launched all tasks");
		exec.shutdown(); // Quit when all tasks complete
	}

	public static void print(Object obj)
	{
		System.out.println(obj);
	}

	public static void print(String format, Object... args)
	{
		System.out.printf(format, args);
	}

}
